package com.misc.pebblewatch;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;

import com.roymam.android.notificationswidget.NotificationData;
import com.roymam.android.notificationswidget.R;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Author: Stephen A. Gutknecht. All Rights Reserved.
 * License: GPLv2 for this class
 * Priority is useful as Canvas allows conditional rules that the user can specify if the notification appears.
 */
public class PebbleCanvasPluginClient extends PebbleCanvasPlugin {

    private static Context myAppContext = null;

    private static final int NOTIFY_PLUGIN_ID = 7300;
    private static final int IMAGE_PLUGIN_ID  = 7310;
    private static final int iconsToPublish = 6;

    // Note: STRINGDEF should end with trailing space.
    private static final String FIELDS_NOTIFICATION1_STRINGDEF = "%T %S %s %F %P1 %W1 ";
    private static final String FIELD_NOTIFICATION1_TITLE     = "%T";
    private static final String FIELD_NOTIFICATION1_SUB1      = "%S";
    private static final String FIELD_NOTIFICATION1_SUB2      = "%s";
    private static final String FIELD_NOTIFICATION1_PKGNAME   = "%F";
    private static final String FIELD_NOTIFICATION1_PRIORITY  = "%P";
    private static final String FIELD_NOTIFICATION1_WHEN      = "%W1";

    // Note: STRINGDEF should end with trailing space.
    private static final String FIELDS_NOTIFICATION2_STRINGDEF = "%Y %D %d %G %P2 %W2 ";
    private static final String FIELD_NOTIFICATION2_TITLE     = "%Y";
    private static final String FIELD_NOTIFICATION2_SUB1      = "%D";
    private static final String FIELD_NOTIFICATION2_SUB2      = "%d";
    private static final String FIELD_NOTIFICATION2_PKGNAME   = "%G";
    private static final String FIELD_NOTIFICATION2_WHEN      = "%W2";

    // Note: STRINGDEF should end with trailing space.
    private static final String FIELDS_NOTIFICATION3_STRINGDEF = "%R %A %a %H %P3 %W3 ";
    private static final String FIELD_NOTIFICATION3_TITLE     = "%R";
    private static final String FIELD_NOTIFICATION3_SUB1      = "%A";
    private static final String FIELD_NOTIFICATION3_SUB2      = "%a";
    private static final String FIELD_NOTIFICATION3_PKGNAME   = "%H";
    private static final String FIELD_NOTIFICATION3_WHEN      = "%W3";

    private static final String FIELD_APPTIME                 = "%Z";
    private static final String FIELD_APPINDEX                = "%z";

    private static final String FIELD_NOTIFICATION_TYPE_PINNED    = "%tp";
    private static final String FIELD_NOTIFICATION_TYPE_EVENT     = "%te";

    // ToDo: time since activity elapsed time as a HH:mm time instead of english expression


    public static void setAppParameters(Context applicationContext) {
        myAppContext = applicationContext;
        triggerWatchPolling(applicationContext);
    }

    @Override
    protected ArrayList<PluginDefinition> get_plugin_definitions(Context context) {
        if (myAppContext == null)
        {
            myAppContext = context.getApplicationContext();
        }

        String vTag = " v1";

        ArrayList<PluginDefinition> pluginDefinitionArray = new ArrayList<PluginDefinition>();
        TextPluginDefinition textPlugin = new TextPluginDefinition();

        textPlugin.id = NOTIFY_PLUGIN_ID;
        textPlugin.name = context.getResources().getString(R.string.title) + vTag;
        textPlugin.default_format_string = FIELD_NOTIFICATION1_SUB1;
        textPlugin.params_description = "no parameters";

        textPlugin.format_mask_descriptions = new ArrayList<String>();
        textPlugin.format_mask_examples = new ArrayList<String>();
        textPlugin.format_masks = new ArrayList<String>();

        String[] splitTagsSource = new String[] { FIELDS_NOTIFICATION1_STRINGDEF, FIELDS_NOTIFICATION2_STRINGDEF, FIELDS_NOTIFICATION3_STRINGDEF };
        for (int loopA = 1; loopA <= 3; loopA++) {
            String[] splitTags = splitTagsSource[loopA - 1].trim().split(" ");
            String outTag = loopA + "";

            textPlugin.format_mask_descriptions.add("Notification " + outTag + " Title");
            textPlugin.format_mask_examples.add("Broadcast successful");
            textPlugin.format_masks.add(splitTags[0]);
            textPlugin.format_mask_descriptions.add("Notification " + outTag + " Subject Line 1");
            textPlugin.format_mask_examples.add("Subject sample text line");
            textPlugin.format_masks.add(splitTags[1]);
            textPlugin.format_mask_descriptions.add("Notification " + outTag + " Subject Line 2");
            textPlugin.format_mask_examples.add("Spillover line?");
            textPlugin.format_masks.add(splitTags[2]);
            textPlugin.format_mask_descriptions.add("Notification " + outTag + " Package name");
            textPlugin.format_mask_examples.add("Twitter App");
            textPlugin.format_masks.add(splitTags[3]);
            textPlugin.format_mask_descriptions.add("Notification " + outTag + " When");
            textPlugin.format_mask_examples.add("23:59:31");
            textPlugin.format_masks.add(splitTags[4]);
            textPlugin.format_mask_descriptions.add("Notification " + outTag + " Priority");
            textPlugin.format_mask_examples.add("0");
            textPlugin.format_masks.add(splitTags[5]);
        }

        // Misc debug fields
        textPlugin.format_mask_descriptions.add("App Time (debug)");
        textPlugin.format_mask_examples.add("23:55:31");
        textPlugin.format_masks.add(FIELD_APPTIME);
        textPlugin.format_mask_descriptions.add("App Index (debug)");
        textPlugin.format_mask_examples.add("1");
        textPlugin.format_masks.add(FIELD_APPINDEX);

        // Misc debug fields
        textPlugin.format_mask_descriptions.add("Type Pinned");
        textPlugin.format_mask_examples.add("0");
        textPlugin.format_masks.add(FIELD_NOTIFICATION_TYPE_PINNED);
        textPlugin.format_mask_descriptions.add("Type Event");
        textPlugin.format_mask_examples.add("0");
        textPlugin.format_masks.add(FIELD_NOTIFICATION_TYPE_EVENT);

        pluginDefinitionArray.add(textPlugin);

        for (int loopA = 1; loopA <= iconsToPublish; loopA++) {
            // Image
            PebbleCanvasPlugin.ImagePluginDefinition imageDefinition = new PebbleCanvasPlugin.ImagePluginDefinition();
            imageDefinition.id = IMAGE_PLUGIN_ID + loopA;
            if (loopA > 3) {
                imageDefinition.name = context.getResources().getString(R.string.title) + vTag + " App Icon Notification " + (loopA - 3);
            }
            else
            {
                imageDefinition.name = context.getResources().getString(R.string.title) + vTag + " Icon Notification " + loopA;

            }
            pluginDefinitionArray.add(imageDefinition);
        }

        return pluginDefinitionArray;
    }


    // Pebble Canvas author: "the static is important because a new instance of the class is created when each message from Canvas is received"
    private static AtomicInteger myNotificationSessionIndex = new AtomicInteger(0);
    private static ArrayList<NotificationData> notificationDataBuffer = new ArrayList<NotificationData>();

    // ToDo: manage the ArrayList and don't just keep adding endlessly.
    public static void forwardNotificationToCanvas(NotificationData incomingNotification)
    {
        int thisIndex = myNotificationSessionIndex.getAndIncrement();
        int contentLength = 0;
        if (incomingNotification.getText() != null)
        {
            contentLength = incomingNotification.getText().length();
        }

        notificationDataBuffer.add(thisIndex, incomingNotification);
        android.util.Log.d("PebbleOut", "incoming notification index: " + thisIndex + " contentLength: " + contentLength);

        try {
            Thread.sleep(15);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        triggerWatchPolling(myAppContext);
    }

    public static void triggerWatchPolling(Context inContext)
    {
        if (inContext == null)
        {
            android.util.Log.e("PebbleOut", "Context is null, can't notify of revised data");
        }
        else {
            PebbleCanvasPlugin.notify_canvas_updates_available(NOTIFY_PLUGIN_ID, inContext);
            for (int loopA = 1; loopA <= iconsToPublish; loopA++) {
                PebbleCanvasPlugin.notify_canvas_updates_available(IMAGE_PLUGIN_ID + loopA, inContext);
            }
        }
    }

    private static final SimpleDateFormat fdHHmm =   new SimpleDateFormat("HH:mm");
    private static final SimpleDateFormat fdHHmmss = new SimpleDateFormat("HH:mm:ss");
    private static final SimpleDateFormat fdhhmm   = new SimpleDateFormat("hh:mm");
    private static final SimpleDateFormat fdhhmmss = new SimpleDateFormat("hh:mm:ss");

    /*
    ToDo: idea... param is date format?
     */
    @Override
    protected String get_format_mask_value(int def_id, String format_mask, Context context, String param) {
        String empty = "";

        android.util.Log.i("PebbleOut", "Pebble Canvas App incoming " + def_id + " format: " + format_mask + " param: " + param);
        if (myAppContext == null)
        {
            myAppContext = context.getApplicationContext();
        }

        if (param == null)
            return empty;

        if (FIELD_NOTIFICATION1_WHEN.equals(format_mask))
        {
            return fdHHmm.format(new Date());
        }
        if (FIELD_APPTIME.equals(format_mask))
        {
            return fdHHmmss.format(new Date());
        }
        if (FIELD_NOTIFICATION1_WHEN.equals(format_mask))
        {
            return fdhhmm.format(new Date());
        }
        if (FIELD_NOTIFICATION1_WHEN.equals(format_mask))
        {
            return fdhhmmss.format(new Date());
        }
        if (FIELD_APPINDEX.equals(format_mask))
        {
            return myNotificationSessionIndex.get() + "";
        }

        int focusedIndexOffset = 0;
        int focusedField = 0;

        if (FIELDS_NOTIFICATION1_STRINGDEF.contains(format_mask + " "))
        {
            focusedIndexOffset = 0;
            focusedField = Arrays.asList(FIELDS_NOTIFICATION1_STRINGDEF.split(" ")).indexOf(format_mask);
        }

        if (FIELDS_NOTIFICATION2_STRINGDEF.contains(format_mask + " "))
        {
            focusedIndexOffset = 1;
            focusedField = Arrays.asList(FIELDS_NOTIFICATION2_STRINGDEF.split(" ")).indexOf(format_mask);
        }

        if (FIELDS_NOTIFICATION3_STRINGDEF.contains(format_mask + " "))
        {
            focusedIndexOffset = 2;
            focusedField = Arrays.asList(FIELDS_NOTIFICATION3_STRINGDEF.split(" ")).indexOf(format_mask);
        }

        if (FIELD_NOTIFICATION_TYPE_PINNED.equals(format_mask))
        {
            focusedIndexOffset = 0;
            focusedField = 100;
        }
        if (FIELD_NOTIFICATION_TYPE_EVENT.equals(format_mask))
        {
            focusedIndexOffset = 0;
            focusedField = 101;
        }

        if (focusedIndexOffset < notificationDataBuffer.size())
        {
            // ToDo: use focusedIndexOffset to get the desired notification of the most recent 3.
            if (focusedIndexOffset >= notificationDataBuffer.size())
            {
                // No available notification.
                return "";
            }

            NotificationData selectedNotification = notificationDataBuffer.get(notificationDataBuffer.size() - 1 - focusedIndexOffset);
            if (selectedNotification != null) {
                switch (focusedField) {
                    case 0:
                        // Too long, split if multiline? \r
                        return selectedNotification.getTitle().toString();
                    case 1:
                    case 2:
                        // Assumption is that the tiniest Canvas font used
                        // Canvas has a 40 character length limit? http://pebblecanvas.blogspot.com/p/faq.html
                        if (selectedNotification.getText() != null) {
                            String fullText = selectedNotification.getText().toString();
                            if (fullText.length() > 40)
                            {
                                String[] splitText = splitIntoLine(fullText, 40);
                                switch (focusedField)
                                {
                                    case 1:
                                        return splitText[0];
                                    case 2:
                                        if (splitText.length > 1)
                                        {
                                            return splitText[1];
                                        }
                                        break;
                                }
                            }
                            else
                            {
                                if (focusedField == 1)
                                    return fullText;
                            }
                        }
                        return "";
                    case 3:
                        return selectedNotification.getPackageName();
                    case 4:
                        return selectedNotification.getTimeText(context).toString();
                    case 5:
                        return selectedNotification.getPriority() + "";
                    case 100:
                        if (selectedNotification.isPinned())
                            return "1";
                        else
                            return "0";
                    case 101:
                        if (selectedNotification.isEvent())
                            return "1";
                        else
                            return "0";
                    default:
                        return "?(ToDo: " + format_mask + ")¿";
                }
            }
            else
            {
                return "?(" + "NULL:0" + ")¿";
            }
        }
        else
        {
            return "";
            //return "?(" + "no data " + notificationDataBuffer.size() + ")¿";
        }

        //return "?(" + format_mask + ")¿";
    }


    /*
    Method Source from : http://stackoverflow.com/questions/7528045/large-string-split-into-lines-with-maximum-length-in-java
     */
    public String[] splitIntoLine(String input, int maxCharInLine){

        try {
            StringTokenizer tok = new StringTokenizer(input, " ");
            StringBuilder output = new StringBuilder(input.length());
            int lineLen = 0;
            while (tok.hasMoreTokens()) {
                String word = tok.nextToken();

                while (word.length() > maxCharInLine) {
                    output.append(word.substring(0, maxCharInLine - lineLen) + "\n");
                    word = word.substring(maxCharInLine - lineLen);
                    lineLen = 0;
                }

                if (lineLen + word.length() > maxCharInLine) {
                    output.append("\n");
                    lineLen = 0;
                }
                output.append(word + " ");

                lineLen += word.length() + 1;
            }

            return output.toString().split("\n");
        }
        catch (Exception e0)
        {
            android.util.Log.e("PebbleOut", "Exception splitting string line " + input);
            e0.printStackTrace();
            // Return the input unmodified, this code needs fixed if we are hitting this.
            return new String[] {input};
        }
    }

    /*
    ToDo: Study the plugin "All My Info Notifications" . It uses Canvas for Pebble's built-in ability to scale images.  forces 11x11 size, lock ratio.
     */
    @Override
    protected Bitmap get_bitmap_value(int def_id, Context context, String param) {
        int focusedIndexOffset = def_id - IMAGE_PLUGIN_ID - 1;
        android.util.Log.i("PebbleOut", "Pebble Canvas App incoming Bitmap request " + def_id + " param: " + param + " raw focusedIndexOffset: " + focusedIndexOffset);

        String tracePath = "";
        Bitmap outResult = null;

        int iconPicked = 0;
        if (focusedIndexOffset > 2) {
            iconPicked = 1;
            focusedIndexOffset = focusedIndexOffset - 3;
        }

        if (myAppContext == null)
        {
            tracePath += "A";
            myAppContext = context.getApplicationContext();
        }

        // Do they want just the plugin App icon?
        if (def_id <= IMAGE_PLUGIN_ID)
        {
            tracePath += "B";
            outResult = BitmapFactory.decodeResource(myAppContext.getResources(), R.drawable.ic_launcher);
        }
        else {
            tracePath += "C";
            if (focusedIndexOffset >= notificationDataBuffer.size()) {
                tracePath += "D";
                // No available notification. Null for blank icon.
                outResult = null;
            }
            else {
                tracePath += "E";
                if (notificationDataBuffer.size() > 1) {
                    tracePath += "F";
                    NotificationData selectedNotification = notificationDataBuffer.get(notificationDataBuffer.size() - 1 - focusedIndexOffset);
                    if (iconPicked == 0) {
                        tracePath += "G";
                        outResult = selectedNotification.getIcon();
                    }
                    else
                    {
                        tracePath += "H";
                        outResult = selectedNotification.getAppIcon();
                    }
                } else {
                    tracePath += "I";
                    outResult = BitmapFactory.decodeResource(myAppContext.getResources(), R.drawable.ic_launcher);
                }
            }
        }

        android.util.Log.i("PebbleOut", "Pebble Canvas App incoming Bitmap request " + def_id + " param: " + param + " offset: " + focusedIndexOffset + " trace: " + tracePath);
        return outResult;
    }
}
